﻿/*
 * SharedPtr.h
 *
 */

#ifndef __GDK_SHAREDPTR_H__
#define __GDK_SHAREDPTR_H__

#include <gdk/core/Types.h>
#include <gdk/core/Memory.h>
#include <gdk/core/Unknown.h>
#include <gdk/core/Exception.h>


namespace gdk
{


	template<class TyClass>
	class SharedPtr
	{
		template<class Tyclass> friend class SharedPtr;

	private:
		template<class Tyclass>
		class Reference : public Unknown
		{
			DECLARE_CLASS_HANDLE(Reference)
			DECLARE_CLASS_INSTANCE1(Reference, Tyclass*)

		private:
			Tyclass*const	_obj;

		protected:
			__INLINE__ Reference(Tyclass *obj)
				: _obj(obj)
			{
			}
			__INLINE__ virtual ~Reference(void)
			{
				if (_obj != NULL)
				{
					delete _obj;
				}
			}

		private:
			__INLINE__ Reference& operator=(const Reference& r)
			{
				GDK_ASSERT(false);

				return *this;
			}
		};

	private:
		TyClass*		_obj;
		Unknown::Handle	_refs;


	private:
		template<class Tyclass>
		__INLINE__ SharedPtr(Tyclass* obj, Unknown* refs)
			: _obj(obj)
			, _refs(refs)
		{
		}

	public:
		template<class Tyclass>
		explicit SharedPtr(Tyclass* obj)
			: _obj(obj)
			, _refs(obj != NULL ? Reference<Tyclass>::createInstance(obj) : NULL)
		{
		}

		__INLINE__ SharedPtr(void)
			: _obj(NULL)
		{
		}
		__INLINE__ SharedPtr(const SharedPtr& r)
		{
			_obj = r._obj;
			_refs = r._refs;
		}
		__INLINE__ SharedPtr& operator=(const SharedPtr& r)
		{
			_obj = r._obj;
			_refs = r._refs;

			return *this;
		}

		template<class Tyclass>
		__INLINE__ SharedPtr(const SharedPtr<Tyclass>& r)
		{
			_obj = r._obj;
			_refs = r._refs;
		}
		template<class Tyclass>
		__INLINE__ SharedPtr& operator=(const SharedPtr<Tyclass>& r)
		{
			_obj = r._obj;
			_refs = r._refs;

			return *this;
		}

		template<class Tyclass>
		__INLINE__ SharedPtr<Tyclass> staticCast(void) const
		{
			return SharedPtr<Tyclass>(static_cast<Tyclass*>(_obj), _refs);
		}
		template<class Tyclass>
		__INLINE__ SharedPtr<Tyclass> dynamicCast(void) const
		{
			Tyclass *obj = dynamic_cast<Tyclass*>(_obj);

			return SharedPtr<Tyclass>(obj, (obj != NULL ? _refs : NULL));
		}

		__INLINE__          operator TyClass*() const { return  _obj; }
		__INLINE__          operator TyClass&() const { return *_obj; }
		__INLINE__ TyClass& operator  *() const { return *_obj; }
		__INLINE__ TyClass* operator ->() const { return  _obj; }

		__INLINE__ bool isNull(void) const { return _obj == NULL; }
		__INLINE__ void setNull(void) { _obj = NULL; _refs = NULL; }
		__INLINE__ TyClass* ptr(void) const { return _obj; }

		template<class Tyclass> __INLINE__ bool operator ==(SharedPtr<Tyclass> const& r) const { return _refs == r._refs; }
		template<class Tyclass> __INLINE__ bool operator !=(SharedPtr<Tyclass> const& r) const { return _refs != r._refs; }

		template<typename Tyis, typename Tyclass> friend Tyis& operator >>(Tyis &is, SharedPtr<Tyclass> &ptr) __THROW1;
		template<typename Tyos, typename Tyclass> friend Tyos& operator <<(Tyos &os, SharedPtr<Tyclass> const &ptr) __THROW1;
	};


	template<typename TyIs, typename TyClass>
	TyIs& operator >>(TyIs &is, SharedPtr<TyClass> &ptr) __THROW1
	{
		char t;
		is >> t;

		switch (t)
		{
		case 'C':
			{
				ptr = SharedPtr<TyClass>(GDK_NEW TyClass());
				is >> *ptr;
			}
			break;

		case 'c':
			{
				ptr.setNull();
			}
			break;

		default:
			{
				String errMsg;
				errMsg.format(__TEXT__("TyIs& operator >>(TyIs &,SharedPtr<" STRING_FMT "> &) Error!"), (Char const*)typeid_className<TyClass>());
				__THROW__((Char const*)errMsg);
			}
			break;
		}

		return is;
	}
	template<typename TyOs, typename TyClass>
	TyOs& operator <<(TyOs &os, SharedPtr<TyClass> const &ptr) __THROW1
	{
		if (ptr._obj != NULL)
		{
			char t('C');
			os << t
			   << *ptr;
		}
		else
		{
			char t('c');
			os << t;
		}
		return os;
	}

}



#endif //__GDK_SHAREDPTR_H__

